//
// Created by benxb on 2021/12/21.
//

#include <common/simple_value.h>
#include <common/exception.h>
#include <float.h>

namespace benxdb {

#define SIMPLE_VALUE_COMPARE_FUNC(OP)                               \
  switch (type_) {                                                  \
    case SimpleType::STYPE_INTEGER:                                       \
      return value_.integer_ OP o.value_.integer_;                  \
    case SimpleType::STYPE_BIGINT:                                        \
      return value_.bigint_ OP o.value_.bigint_;                    \
    case SimpleType::STYPE_FLOAT:                                         \
      return value_.float_ OP o.value_.float_;                      \
    case SimpleType::STYPE_DECIMAL:                                       \
      return value_.decimal_ OP o.value_.decimal_;                  \
    default:                                                        \
      throw Exception(ExceptionType::INCOMPATIBLE_TYPE, "Invalid Type for compare Value");   \
  }

#define SIMPLE_VALUE_MODIFY_FUNC(OP)                                                    \
  switch (type_) {                                                                      \
    case SimpleType::STYPE_INTEGER:                                                           \
      return SimpleValue(type_, value_.integer_ OP o.value_.integer_);                  \
    case SimpleType::STYPE_BIGINT:                                                            \
      return SimpleValue(type_, value_.bigint_ OP o.value_.bigint_);                    \
    case SimpleType::STYPE_FLOAT:                                                             \
      return SimpleValue(type_, value_.float_ OP o.value_.float_);                      \
    case SimpleType::STYPE_DECIMAL:                                                           \
      return SimpleValue(type_, value_.decimal_ OP o.value_.decimal_);                  \
    default:                                                                            \
      throw Exception(ExceptionType::INCOMPATIBLE_TYPE, "Invalid Type for modify Value");     \
  }

SimpleValue::SimpleValue(SimpleType type, const char *data) : type_(type) {
    switch (type) {
        case SimpleType::STYPE_INTEGER:
            value_.integer_ = *reinterpret_cast<const int32_t *>(data);
            break;
        case SimpleType::STYPE_FLOAT:
            value_.float_ = *reinterpret_cast<const float *> (data);
            break;
        case SimpleType::STYPE_DECIMAL:
            value_.decimal_ = *reinterpret_cast<const double *> (data);
            break;
        case SimpleType::STYPE_BIGINT:
            value_.bigint_ = *reinterpret_cast<const int64_t *>(data);
            break;
        case SimpleType::STYPE_TIMESTAMP:
            value_.timestamp_ =  *reinterpret_cast<const uint64_t *>(data);
            break;
        default:
            throw Exception(ExceptionType::INCOMPATIBLE_TYPE, "Invalid Type for SimpleValue constructor");
    }
}

bool SimpleValue::CompareEquals(const SimpleValue &o) const {
    SIMPLE_VALUE_COMPARE_FUNC(<)
}

bool SimpleValue::CompareNotEquals(const SimpleValue &o) const {
    SIMPLE_VALUE_COMPARE_FUNC(!=)
}

bool SimpleValue::CompareLessThan(const SimpleValue &o) const {
    SIMPLE_VALUE_COMPARE_FUNC(<)
}

bool SimpleValue::CompareLessThanEquals(const SimpleValue &o) const {
    SIMPLE_VALUE_COMPARE_FUNC(<=)
}

bool SimpleValue::CompareGreaterThan(const SimpleValue &o) const {
    SIMPLE_VALUE_COMPARE_FUNC(>)
}

bool SimpleValue::CompareGreaterThanEquals(const SimpleValue &o) const {
    SIMPLE_VALUE_COMPARE_FUNC(>=)
}

int SimpleValue::GetSize() {
    switch (type_) {
        case SimpleType::STYPE_INTEGER:
            return sizeof(int32_t);
        case SimpleType::STYPE_FLOAT:
            return sizeof(float);
        case SimpleType::STYPE_DECIMAL:
            return sizeof(double);
        case SimpleType::STYPE_BIGINT:
            return sizeof(int64_t);
        case SimpleType::STYPE_TIMESTAMP:
            return sizeof(uint64_t);
        default:
            throw Exception(ExceptionType::INCOMPATIBLE_TYPE, "Invalid Type for GetSize Value");
    }
}

SimpleValue SimpleValue::Add(const SimpleValue &o) {
    SIMPLE_VALUE_MODIFY_FUNC(+)
}

SimpleValue::SimpleValue(SimpleType type, int32_t val) : type_(type) {
    value_.integer_ = val;
}

SimpleValue::SimpleValue(SimpleType type, float val) : type_(type) {
    value_.float_ = val;
}

SimpleValue::SimpleValue(SimpleType type, double val) : type_(type) {
    if (type == STYPE_FLOAT) {
        value_.float_ = val;
    } else {
        value_.decimal_ = val;
    }
}

SimpleValue::SimpleValue(SimpleType type, int64_t val) : type_(type) {
    value_.bigint_ = val;
}

SimpleValue::SimpleValue(SimpleType type, uint64_t val) : type_(type) {
    value_.timestamp_ = val;
}

SimpleValue SimpleValue::Subtract(const SimpleValue &o) {
    SIMPLE_VALUE_MODIFY_FUNC(-)
}

SimpleValue SimpleValue::Multiply(const SimpleValue &o) {
    SIMPLE_VALUE_MODIFY_FUNC(*)
}

SimpleValue SimpleValue::Divide(const SimpleValue &o) {
    SIMPLE_VALUE_MODIFY_FUNC(/)
}

int SimpleValue::SerializeTo(char *storage) {
    switch (type_) {
        case SimpleType::STYPE_INTEGER:
            *reinterpret_cast<int32_t *>(storage) = value_.integer_;
            return sizeof(int32_t);
        case SimpleType::STYPE_FLOAT:
            *reinterpret_cast<float *>(storage) = value_.float_;
            return sizeof(float);
        case SimpleType::STYPE_DECIMAL:
            *reinterpret_cast<double *>(storage) = value_.decimal_;
            return sizeof(double);
        case SimpleType::STYPE_BIGINT:
            *reinterpret_cast<int64_t *>(storage) = value_.bigint_;
            return sizeof(int64_t);
        case SimpleType::STYPE_TIMESTAMP:
            *reinterpret_cast<uint64_t *>(storage) = value_.timestamp_;
            return sizeof(uint64_t);
        default:
            throw Exception(ExceptionType::INCOMPATIBLE_TYPE, "Invalid Type for SerializeTo");
    }
}

SimpleValue SimpleValue::DeserializeFrom(const char *storage, SimpleType type) {
    return SimpleValue(type, storage);
}

int SimpleValue::GetSizeOfType(SimpleType type) {
    switch (type) {
        case SimpleType::STYPE_INTEGER:
            return sizeof(int32_t);
        case SimpleType::STYPE_FLOAT:
            return sizeof(float);
        case SimpleType::STYPE_DECIMAL:
            return sizeof(double);
        case SimpleType::STYPE_BIGINT:
            return sizeof(int64_t);
        case SimpleType::STYPE_TIMESTAMP:
            return sizeof(uint64_t);
        default:
            throw Exception(ExceptionType::INCOMPATIBLE_TYPE, "Invalid Type for GetSizeOfType");
    }
}

SimpleValue SimpleValue::GetMinValueOfType(SimpleType type) {
    switch (type) {
        case SimpleType::STYPE_INTEGER:
            return SimpleValue(type, INT32_MIN);
        case SimpleType::STYPE_FLOAT:
            return SimpleValue(type, FLT_MIN);
        case SimpleType::STYPE_DECIMAL:
            return SimpleValue(type, DBL_MIN);
        case SimpleType::STYPE_BIGINT:
            return SimpleValue(type, INT64_MIN);
        case SimpleType::STYPE_TIMESTAMP:
            return SimpleValue(type, 0);
        default:
            throw Exception(ExceptionType::INCOMPATIBLE_TYPE, "Invalid Type for GetSizeOfType");
    }
}

SimpleValue SimpleValue::GetMaxValueOfType(SimpleType type) {
    switch (type) {
        case SimpleType::STYPE_INTEGER:
            return SimpleValue(type, INT32_MAX);
        case SimpleType::STYPE_FLOAT:
            return SimpleValue(type, FLT_MAX);
        case SimpleType::STYPE_DECIMAL:
            return SimpleValue(type, DBL_MAX);
        case SimpleType::STYPE_BIGINT:
            return SimpleValue(type, INT64_MAX);
        case SimpleType::STYPE_TIMESTAMP:
            return SimpleValue(type, UINT64_MAX);
        default:
            throw Exception(ExceptionType::INCOMPATIBLE_TYPE, "Invalid Type for GetSizeOfType");
    }
}

}